package top.bulk.retry.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;
import top.bulk.retry.service.TestRetryTemplateService;

/**
 * 测试spring-retry编程式 方式
 *
 * @author 散装java
 * @date 2024-07-03
 */
@Service
@Slf4j
public class TestRetryTemplateServiceImpl implements TestRetryTemplateService {

    /**
     * 非注解式重试 - 编程式重试
     */
    @Override
    public String testTemplate1() {
        RetryTemplate retryTemplate = new RetryTemplate();

        // 创建并设置一个简单重试策略，限制最大重试次数为3次
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        // 设置最大重试次数为3
        retryPolicy.setMaxAttempts(3);
        retryTemplate.setRetryPolicy(retryPolicy);

        // FixedBackOffPolicy 是一个固定间隔的退避策略。它在每次重试之间使用固定的等待时间。
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        // 设置固定的重试间隔为1秒
        backOffPolicy.setBackOffPeriod(1000);

        // ExponentialBackOffPolicy 是一个指数退避的退避策略。它在每次重试时增加重试的等待时间，使得重试操作在间隔时间上逐渐增加。
        // ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
        // // 初始重试间隔为1秒
        // exponentialBackOffPolicy.setInitialInterval(1000);
        // // 重试间隔的倍数为2
        // exponentialBackOffPolicy.setMultiplier(2);
        // // 最大重试间隔为5秒
        // exponentialBackOffPolicy.setMaxInterval(5000);

        // UniformRandomBackOffPolicy 是一个随机退避的退避策略。它在每次重试时等待一个随机的时间段，以减少重试操作的同时发生。
        // UniformRandomBackOffPolicy uniformRandomBackOffPolicy = new UniformRandomBackOffPolicy();
        // // 设置最小的重试间隔为1秒
        // uniformRandomBackOffPolicy.setMinBackOffPeriod(1000);
        // // 设置最大的重试间隔为5秒
        // uniformRandomBackOffPolicy.setMaxBackOffPeriod(5000);

        // 设置退避策略
        retryTemplate.setBackOffPolicy(backOffPolicy);

        // context和 recoveryCallback 是 RetryContext 对象
        String res = retryTemplate.execute(context -> {
            log.info("执行 retryTemplate.execute");
            // 需要重试的方法体
            if (context.getRetryCount() < 3) {
                throw new RuntimeException("假装异常");
            }
            return "testOk";
        }, recoveryCallback -> {
            log.info("recoveryCallback 重试次数:{}", recoveryCallback.getRetryCount());
            return "进入 recoveryCallback";
        });
        return res;
    }
}
